#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <vector>
#include <string>
using namespace std;
const int threadnum = 5; // 创建线程的数量

/*void *handlertask(void *args)
{
    //string threadname = (char *)args;//threadname在线程自身的独立栈上保存,虽然多个线程执行同一个handlertask()函数,彼此之间无影响
    const char* threadname=(char*)args;
    while (true)
    {
        sleep(1);
        cout << "I am " << threadname << endl;
    }
}
// 1. 创建多个(threadnum)线程
int main()
{
    char threadname[64];//(bug 2)
    vector<pthread_t> threads; // vector中保存线程的用户级标识tid
    for (int i = 0; i < threadnum; i++)
    {
        //char threadname[64];(bug 1)
        snprintf(threadname, sizeof(threadname), "thread -%d", i + 1);
        pthread_t tid;
        pthread_create(&tid, nullptr, handlertask, threadname);

        threads.push_back(tid);
    }

    for(auto& tid:threads)
    {
        pthread_join(tid,nullptr);
    }

    return 0;
}
*/

// 运行结果:
// I am thread -2
// I am thread -5
// I am thread -5
// I am thread -5
// I am thread -5
// I am thread -5

// 原因: pthread_create()函数创建线程时,传递给新线程的参数为缓冲区char threadname[64]的地址,
// handlertask()函数里面的指针threadname指向外部的缓冲区,char threadname[64]定义在局部代码块之中,单趟循环结束之后,缓冲区被释放
// 此时新线程虽然获得缓冲区的地址,主线程已经释放掉缓冲区的空间,由于主线程不断创建新线程,此块缓冲区的空间被再次开辟,缓冲区保存的字符串已经发生更改;
// 从而原先创建的线程受到影响;
// 将主线程的缓冲区放到单趟循环体的外部(主线程内部)依然会存在同样的问题,因为新线程中threadname指针会指向同一个外部缓冲区,
// 而主线程不断在进行覆盖式写入;

// 解决方案:
// 给每一个线程申请独立的线程空间,在堆区开辟空间,只要不手动释放,空间一直存在;

/*void *handlertask(void *args)
{
    //string threadname = (char *)args;
    const char* threadname=(char*)args;
    while (true)
    {
        sleep(1);
        cout << "I am " << threadname << endl;
    }

    delete []threadname;//释放堆空间
}
int main()
{
    vector<pthread_t> threads; // vector中保存线程的用户级标识tid
    for (int i = 0; i < threadnum; i++)
    {
        char* threadname=new char[64];//每次循环都会开辟堆区的空间
        snprintf(threadname, 64, "thread -%d", i + 1);
        pthread_t tid;
        pthread_create(&tid, nullptr, handlertask, threadname);

        threads.push_back(tid);
    }

    for(auto& tid:threads)
    {
        pthread_join(tid,nullptr);
    }
    return 0;
}*/

// 2.线程函数的参数/返回值为void*,可以接收任意类型,可以传递用户自定义对象指针

//Task---每个线程执行的任务封装
class Task
{
public:
    Task(int x, int y)
        : _x(x), _y(y)
    {
    }
    int Execute()
    {
        return _x + _y;
    }

private:
    int _x;
    int _y;
};

//ThreadData---创建线程需要传递的对象指针
class ThreadData
{
public:
    ThreadData(string threadname,int x,int y)
    :_threadname(threadname)
    , _t(x,y)
    {
    }

    string threadname()
    {
        return _threadname;
    }

    int runtask()
    {
        return _t.Execute();
    }

private:
    string _threadname; // 线程名
    Task _t;           // 线程执行的任务
};

//situation---线程执行结束收集各个线程任务执行情况
class situation
{
public:
    situation()
    {}
    void GetResult(int result,string& threadname)
    {
        _result=result;
        _threadname=threadname;
    }
    void print()
    {
        cout<<_threadname<<" : "<<_result<<endl;
    }
private:
    int _result;//执行结果
    string _threadname;//属于哪一个线程
};

void *handlertask(void *args)
{
    ThreadData* td=(ThreadData*)args;

    string name=td->threadname();

    situation* res=new situation();
    int result=td->runtask();
    
    res->GetResult(result,name);
    //cout<<name<<" run result:"<<result<<endl;
    delete td;

    sleep(2);
    return res;
}
int main()
{
    vector<pthread_t> threads; // vector中保存线程的用户级标识tid
    for (int i = 0; i < threadnum; i++)
    {
        char threadname[64]; // 每次循环都会开辟堆区的空间
        snprintf(threadname, 64, "thread -%d", i + 1);

        //传递用户自定义对象
        ThreadData* td=new ThreadData(threadname,10,20);
        pthread_t tid;
        pthread_create(&tid, nullptr, handlertask,(void*)td);

        threads.push_back(tid);
    }
    vector<situation*> result;//保存对象(对象保存运行结果)指针
    void* ret=nullptr;
    for (auto &tid : threads)
    {
        pthread_join(tid, &ret);
        result.push_back((situation*)ret);
    }
    for(auto& res:result)
    {
       res->print();
       delete res;
    }

    return 0;
}